<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Suna Gateway 实时监控仪表板</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            color: #333;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
            padding: 20px;
        }

        .header {
            text-align: center;
            color: white;
            margin-bottom: 30px;
        }

        .header h1 {
            font-size: 3rem;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 15px;
        }

        .status-indicator {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #48bb78;
            animation: pulse 2s infinite;
        }

        @keyframes pulse {
            0% { opacity: 1; transform: scale(1); }
            50% { opacity: 0.6; transform: scale(1.1); }
            100% { opacity: 1; transform: scale(1); }
        }

        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }

        .stat-card {
            background: white;
            border-radius: 15px;
            padding: 25px;
            text-align: center;
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
            transition: transform 0.3s ease;
            position: relative;
            overflow: hidden;
        }

        .stat-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 4px;
            background: linear-gradient(90deg, #667eea, #764ba2);
        }

        .stat-card:hover {
            transform: translateY(-5px);
        }

        .stat-icon {
            font-size: 2.5rem;
            margin-bottom: 15px;
        }

        .stat-number {
            font-size: 2rem;
            font-weight: bold;
            margin-bottom: 10px;
            color: #2d3748;
        }

        .stat-label {
            color: #718096;
            font-size: 0.9rem;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        .main-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }

        .logs-section {
            grid-column: span 2;
        }

        .card {
            background: white;
            border-radius: 15px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
        }

        .card h3 {
            margin-bottom: 20px;
            color: #4a5568;
            border-bottom: 2px solid #e2e8f0;
            padding-bottom: 10px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .logs-container {
            background: #1a1a1a;
            border-radius: 10px;
            padding: 20px;
            height: 500px;
            overflow-y: auto;
            font-family: 'Courier New', Monaco, monospace;
            font-size: 13px;
            line-height: 1.4;
            position: relative;
        }

        .log-entry {
            margin-bottom: 8px;
            padding: 6px 10px;
            border-radius: 4px;
            border-left: 3px solid transparent;
            animation: fadeIn 0.3s ease-in;
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .log-gateway {
            background: rgba(102, 126, 234, 0.1);
            border-left-color: #667eea;
            color: #a5b4fc;
        }

        .log-auth {
            background: rgba(245, 158, 11, 0.1);
            border-left-color: #f59e0b;
            color: #fcd34d;
        }

        .log-rate-limit {
            background: rgba(239, 68, 68, 0.1);
            border-left-color: #ef4444;
            color: #fca5a5;
        }

        .log-error {
            background: rgba(220, 38, 38, 0.1);
            border-left-color: #dc2626;
            color: #fca5a5;
        }

        .log-success {
            background: rgba(34, 197, 94, 0.1);
            border-left-color: #22c55e;
            color: #86efac;
        }

        .log-info {
            background: rgba(59, 130, 246, 0.1);
            border-left-color: #3b82f6;
            color: #93c5fd;
        }

        .log-timestamp {
            color: #6b7280;
            font-weight: bold;
        }

        .log-level {
            font-weight: bold;
            padding: 2px 6px;
            border-radius: 3px;
            font-size: 11px;
        }

        .service-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 10px;
            background: #f8fafc;
            transition: all 0.3s ease;
        }

        .service-item:hover {
            background: #edf2f7;
            transform: translateX(5px);
        }

        .service-name {
            font-weight: bold;
            color: #2d3748;
        }

        .service-url {
            color: #718096;
            font-size: 0.9rem;
        }

        .service-status {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .status-healthy {
            background: #48bb78;
        }

        .status-unhealthy {
            background: #f56565;
        }

        .controls {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
            flex-wrap: wrap;
        }

        .btn {
            padding: 8px 16px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.9rem;
            font-weight: 500;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            gap: 5px;
        }

        .btn-primary {
            background: #667eea;
            color: white;
        }

        .btn-primary:hover {
            background: #5a67d8;
        }

        .btn-secondary {
            background: #e2e8f0;
            color: #4a5568;
        }

        .btn-secondary:hover {
            background: #cbd5e0;
        }

        .btn-danger {
            background: #f56565;
            color: white;
        }

        .btn-danger:hover {
            background: #e53e3e;
        }

        .auto-scroll {
            background: #48bb78;
            color: white;
        }

        .log-filter {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
            flex-wrap: wrap;
        }

        .filter-btn {
            padding: 5px 12px;
            border: 2px solid #e2e8f0;
            background: white;
            border-radius: 20px;
            cursor: pointer;
            font-size: 0.8rem;
            transition: all 0.3s ease;
        }

        .filter-btn.active {
            border-color: #667eea;
            background: #667eea;
            color: white;
        }

        .metrics-row {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 20px;
        }

        .metric-card {
            background: #f8fafc;
            padding: 15px;
            border-radius: 8px;
            text-align: center;
        }

        .metric-value {
            font-size: 1.5rem;
            font-weight: bold;
            color: #2d3748;
        }

        .metric-label {
            font-size: 0.8rem;
            color: #718096;
            margin-top: 5px;
        }

        .loading {
            display: inline-block;
            width: 16px;
            height: 16px;
            border: 2px solid #f3f3f3;
            border-top: 2px solid #667eea;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .connection-status {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 10px 15px;
            border-radius: 25px;
            font-size: 0.9rem;
            font-weight: bold;
            z-index: 1000;
            transition: all 0.3s ease;
        }

        .connection-online {
            background: #48bb78;
            color: white;
        }

        .connection-offline {
            background: #f56565;
            color: white;
        }

        @media (max-width: 768px) {
            .main-grid {
                grid-template-columns: 1fr;
            }

            .logs-section {
                grid-column: span 1;
            }

            .header h1 {
                font-size: 2rem;
            }
        }

        .chart-container {
            height: 300px;
            position: relative;
        }
    </style>
</head>
<body>
    <div class="connection-status" id="connectionStatus">
        <span id="connectionIcon">🟢</span> 已连接
    </div>

    <div class="container">
        <div class="header">
            <h1>
                <span class="status-indicator" id="gatewayStatus"></span>
                🚀 Suna Gateway 实时监控
            </h1>
            <p>统一网关服务实时监控仪表板</p>
        </div>

        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-icon">🏥</div>
                <div class="stat-number" id="totalServices">-</div>
                <div class="stat-label">总服务数</div>
            </div>

            <div class="stat-card">
                <div class="stat-icon">✅</div>
                <div class="stat-number" id="healthyServices">-</div>
                <div class="stat-label">健康服务</div>
            </div>

            <div class="stat-card">
                <div class="stat-icon">📊</div>
                <div class="stat-number" id="totalRequests">0</div>
                <div class="stat-label">总请求数</div>
            </div>

            <div class="stat-card">
                <div class="stat-icon">⚡</div>
                <div class="stat-number" id="avgResponseTime">-</div>
                <div class="stat-label">平均响应时间</div>
            </div>

            <div class="stat-card">
                <div class="stat-icon">🔄</div>
                <div class="stat-number" id="requestsPerMin">0</div>
                <div class="stat-label">每分钟请求</div>
            </div>

            <div class="stat-card">
                <div class="stat-icon">❌</div>
                <div class="stat-number" id="errorRate">0%</div>
                <div class="stat-label">错误率</div>
            </div>
        </div>

        <div class="main-grid">
            <div class="card">
                <h3>🏥 服务状态</h3>
                <div id="servicesList"></div>
            </div>

            <div class="card">
                <h3>📈 实时指标</h3>
                <div class="metrics-row">
                    <div class="metric-card">
                        <div class="metric-value" id="activeConnections">0</div>
                        <div class="metric-label">活跃连接</div>
                    </div>
                    <div class="metric-card">
                        <div class="metric-value" id="queuedRequests">0</div>
                        <div class="metric-label">队列请求</div>
                    </div>
                </div>
                <div class="metrics-row">
                    <div class="metric-card">
                        <div class="metric-value" id="memoryUsage">-</div>
                        <div class="metric-label">内存使用</div>
                    </div>
                    <div class="metric-card">
                        <div class="metric-value" id="uptime">-</div>
                        <div class="metric-label">运行时间</div>
                    </div>
                </div>
            </div>
        </div>

        <div class="card logs-section">
            <h3>
                📋 实时日志监控
                <div class="controls">
                    <button class="btn btn-primary" onclick="dashboard.toggleAutoScroll()" id="autoScrollBtn">
                        📌 自动滚动
                    </button>
                    <button class="btn btn-secondary" onclick="dashboard.clearLogs()">
                        🗑️ 清空日志
                    </button>
                    <button class="btn btn-secondary" onclick="dashboard.exportLogs()">
                        💾 导出日志
                    </button>
                    <span class="btn btn-secondary">
                        📝 日志数量: <span id="logCount">0</span>
                    </span>
                </div>
            </h3>

            <div class="log-filter">
                <div class="filter-btn active" data-filter="all">全部</div>
                <div class="filter-btn" data-filter="gateway">网关</div>
                <div class="filter-btn" data-filter="auth">认证</div>
                <div class="filter-btn" data-filter="rate-limit">限流</div>
                <div class="filter-btn" data-filter="error">错误</div>
                <div class="filter-btn" data-filter="success">成功</div>
            </div>

            <div class="logs-container" id="logsContainer"></div>
        </div>
    </div>

    <script>
        class GatewayDashboard {
            constructor() {
                this.logs = [];
                this.autoScroll = true;
                this.currentFilter = 'all';
                this.maxLogs = 1000;
                this.isConnected = false;
                this.stats = {
                    totalRequests: 0,
                    totalErrors: 0,
                    responseTimes: [],
                    requestsThisMinute: 0
                };

                this.init();
            }

            init() {
                this.setupEventListeners();
                this.startDataPolling();
                this.startLogPolling();
                this.startStatsUpdate();
                this.updateConnectionStatus(true);

                // 添加初始日志
                this.addLog('info', 'Dashboard初始化完成', 'system');
                this.addLog('info', '开始监控Gateway日志...', 'system');
            }

            setupEventListeners() {
                // 日志过滤器
                document.querySelectorAll('.filter-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
                        e.target.classList.add('active');
                        this.currentFilter = e.target.dataset.filter;
                        this.renderLogs();
                    });
                });

                // 自动滚动到底部
                const logsContainer = document.getElementById('logsContainer');
                logsContainer.addEventListener('scroll', () => {
                    const isAtBottom = logsContainer.scrollTop + logsContainer.clientHeight >= logsContainer.scrollHeight - 5;
                    if (!isAtBottom) {
                        this.autoScroll = false;
                        this.updateAutoScrollButton();
                    }
                });
            }

            async startDataPolling() {
                const pollData = async () => {
                    try {
                        await Promise.all([
                            this.loadServices(),
                            this.loadStats()
                        ]);
                        this.updateConnectionStatus(true);
                    } catch (error) {
                        console.error('数据轮询失败:', error);
                        this.updateConnectionStatus(false);
                        this.addLog('error', `数据加载失败: ${error.message}`, 'system');
                    }
                };

                await pollData();
                setInterval(pollData, 5000); // 每5秒更新一次
            }

            async startLogPolling() {
                // 模拟实时日志 - 在实际环境中，这里应该连接到WebSocket或轮询日志API
                const simulateLogs = () => {
                    const logTypes = [
                        { type: 'gateway', level: 'info', message: 'Gateway拦截请求: GET suna-ai/test' },
                        { type: 'auth', level: 'info', message: '认证成功: user_123' },
                        { type: 'gateway', level: 'success', message: '请求处理完成: 200 | 45ms' },
                        { type: 'rate-limit', level: 'warning', message: '限流检查: 剩余98次' }
                    ];

                    if (Math.random() < 0.3) { // 30%概率生成日志
                        const randomLog = logTypes[Math.floor(Math.random() * logTypes.length)];
                        this.addLog(randomLog.level, randomLog.message, randomLog.type);

                        // 更新统计
                        this.stats.totalRequests++;
                        this.stats.requestsThisMinute++;

                        if (randomLog.level === 'error') {
                            this.stats.totalErrors++;
                        }

                        // 添加响应时间
                        const responseTime = Math.random() * 200 + 20;
                        this.stats.responseTimes.push(responseTime);
                        if (this.stats.responseTimes.length > 100) {
                            this.stats.responseTimes.shift();
                        }
                    }
                };

                setInterval(simulateLogs, 2000); // 每2秒可能生成日志
            }

            async startStatsUpdate() {
                setInterval(() => {
                    // 重置每分钟计数器
                    this.stats.requestsThisMinute = 0;

                    // 更新统计显示
                    this.updateStatsDisplay();
                }, 60000); // 每分钟重置

                // 每秒更新显示
                setInterval(() => {
                    this.updateStatsDisplay();
                }, 1000);
            }

            updateStatsDisplay() {
                document.getElementById('totalRequests').textContent = this.stats.totalRequests.toLocaleString();
                document.getElementById('requestsPerMin').textContent = this.stats.requestsThisMinute;

                const errorRate = this.stats.totalRequests > 0 ?
                    (this.stats.totalErrors / this.stats.totalRequests * 100).toFixed(1) : 0;
                document.getElementById('errorRate').textContent = errorRate + '%';

                const avgResponseTime = this.stats.responseTimes.length > 0 ?
                    (this.stats.responseTimes.reduce((a, b) => a + b, 0) / this.stats.responseTimes.length).toFixed(1) : 0;
                document.getElementById('avgResponseTime').textContent = avgResponseTime + 'ms';

                // 模拟其他指标
                document.getElementById('activeConnections').textContent = Math.floor(Math.random() * 20) + 5;
                document.getElementById('queuedRequests').textContent = Math.floor(Math.random() * 5);
                document.getElementById('memoryUsage').textContent = (Math.random() * 30 + 40).toFixed(1) + '%';
            }

            async loadServices() {
                try {
                    const response = await fetch('/api/v1/services');
                    if (response.ok) {
                        const services = await response.json();
                        this.renderServices(services);

                        const totalServices = Object.keys(services).length;
                        const healthyServices = Object.values(services).filter(s => s.is_healthy).length;

                        document.getElementById('totalServices').textContent = totalServices;
                        document.getElementById('healthyServices').textContent = healthyServices;
                    }
                } catch (error) {
                    console.error('加载服务失败:', error);
                }
            }

            async loadStats() {
                try {
                    const response = await fetch('/api/dashboard/stats');
                    if (response.ok) {
                        const stats = await response.json();
                        // 处理统计数据
                    }
                } catch (error) {
                    console.error('加载统计失败:', error);
                }
            }

            renderServices(services) {
                const servicesList = document.getElementById('servicesList');
                servicesList.innerHTML = '';

                Object.entries(services).forEach(([name, status]) => {
                    const serviceItem = document.createElement('div');
                    serviceItem.className = 'service-item';

                    serviceItem.innerHTML = `
                        <div>
                            <div class="service-name">${name}</div>
                            <div class="service-url">${status.url}</div>
                        </div>
                        <div class="service-status">
                            <div class="status-indicator ${status.is_healthy ? 'status-healthy' : 'status-unhealthy'}"></div>
                            <span>${status.is_healthy ? '健康' : '异常'}</span>
                            <span style="margin-left: 10px; color: #718096;">${status.response_time || 'N/A'}</span>
                        </div>
                    `;

                    servicesList.appendChild(serviceItem);
                });
            }

            addLog(level, message, type = 'info') {
                const timestamp = new Date().toLocaleTimeString();
                const logEntry = {
                    id: Date.now() + Math.random(),
                    timestamp,
                    level,
                    message,
                    type,
                    time: new Date()
                };

                this.logs.unshift(logEntry);

                // 限制日志数量
                if (this.logs.length > this.maxLogs) {
                    this.logs = this.logs.slice(0, this.maxLogs);
                }

                this.renderLogs();
                this.updateLogCount();
            }

            renderLogs() {
                const logsContainer = document.getElementById('logsContainer');
                const filteredLogs = this.currentFilter === 'all' ?
                    this.logs : this.logs.filter(log => log.type === this.currentFilter);

                logsContainer.innerHTML = filteredLogs.map(log => {
                    const logClass = this.getLogClass(log.type, log.level);
                    return `
                        <div class="log-entry ${logClass}">
                            <span class="log-timestamp">[${log.timestamp}]</span>
                            <span class="log-level">${log.level.toUpperCase()}</span>
                            ${log.message}
                        </div>
                    `;
                }).join('');

                if (this.autoScroll) {
                    logsContainer.scrollTop = logsContainer.scrollHeight;
                }
            }

            getLogClass(type, level) {
                if (level === 'error') return 'log-error';
                if (level === 'warning') return 'log-rate-limit';
                if (level === 'success') return 'log-success';

                switch (type) {
                    case 'gateway': return 'log-gateway';
                    case 'auth': return 'log-auth';
                    case 'rate-limit': return 'log-rate-limit';
                    default: return 'log-info';
                }
            }

            updateLogCount() {
                document.getElementById('logCount').textContent = this.logs.length;
            }

            toggleAutoScroll() {
                this.autoScroll = !this.autoScroll;
                this.updateAutoScrollButton();

                if (this.autoScroll) {
                    const logsContainer = document.getElementById('logsContainer');
                    logsContainer.scrollTop = logsContainer.scrollHeight;
                }
            }

            updateAutoScrollButton() {
                const btn = document.getElementById('autoScrollBtn');
                btn.textContent = this.autoScroll ? '📌 自动滚动' : '📌 手动滚动';
                btn.className = this.autoScroll ? 'btn auto-scroll' : 'btn btn-secondary';
            }

            clearLogs() {
                if (confirm('确定要清空所有日志吗？')) {
                    this.logs = [];
                    this.renderLogs();
                    this.updateLogCount();
                    this.addLog('info', '日志已清空', 'system');
                }
            }

            exportLogs() {
                const logText = this.logs.map(log =>
                    `[${log.timestamp}] ${log.level.toUpperCase()} [${log.type}] ${log.message}`
                ).join('\n');

                const blob = new Blob([logText], { type: 'text/plain' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `gateway-logs-${new Date().toISOString().slice(0, 19)}.txt`;
                a.click();
                URL.revokeObjectURL(url);

                this.addLog('info', '日志已导出', 'system');
            }

            updateConnectionStatus(isConnected) {
                this.isConnected = isConnected;
                const statusEl = document.getElementById('connectionStatus');
                const iconEl = document.getElementById('connectionIcon');

                if (isConnected) {
                    statusEl.className = 'connection-status connection-online';
                    statusEl.innerHTML = '<span id="connectionIcon">🟢</span> 已连接';
                } else {
                    statusEl.className = 'connection-status connection-offline';
                    statusEl.innerHTML = '<span id="connectionIcon">🔴</span> 连接断开';
                }
            }
        }

        // 全局Dashboard实例
        let dashboard;

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            dashboard = new GatewayDashboard();
        });
    </script>
</body>
</html>